package com.wanji.single_point.service.impl;

import com.wanji.single_point.entity.Count;
import com.wanji.single_point.pojo.CountResult;
import com.wanji.single_point.pojo.PutParam;
import com.wanji.single_point.result.StatePerceiveResult;
import com.wanji.single_point.service.CountService;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xinyingjie
 * @since 2022-07-14
 */
@Service
public class CountServiceImpl implements CountService {


    private static Map<String,StatePerceiveResult> resultMap = new ConcurrentHashMap<>();
    private static volatile CountResult countResult = new CountResult();

    private static final int target_num_index = 0;
    private static final int sum_smallcar_index = 1;
    private static final int sum_midcar_index = 2;
    private static final int sum_bigcar_index = 3;
    private static final int avg_speed_index = 4;
    private static final int occupancy_index = 5;  //时间占有率
    private static final int headway_index = 6;   // 平均车头时距
    private static final int gap_index = 7;      // 平均车身间距


    private static final int avg_speed_thread = 5;
    private static final int occupancy_thread = 15;
    private static final int headway_thread = 1;
    private static final int gap_thread = 1;

    private static final int match_time = 30;


    @Override
    public void putData(String userId, Count countReal,Count countTest, PutParam param ) {
        StatePerceiveResult result = null;
        if (!resultMap.containsKey(userId)){
            result = new StatePerceiveResult();
            result = fillArray(result);

        }else {
            result = resultMap.get(userId);
        }
//        System.out.println(Arrays.toString(result.getNowRealNum()));
        result = statePerceiveCount(userId,param,result, countReal, countTest);
//        System.out.println(result);
        resultMap.put(userId,result);

    }

    @Override
    public CountResult getResult(String userId) {
        StatePerceiveResult result = resultMap.get(userId);
        if (result != null){
            countResult.setNowRealNum(result.getNowRealNum());
            countResult.setNowTestNum(result.getNowTestNum());
            countResult.setTotalRealNum(result.getTotalRealNum());
            countResult.setTotalTestNum(result.getTotalTestNum());
            countResult.setTotalRate(result.getTotalRate());
            return countResult;
        }else {
            StatePerceiveResult result1 = new StatePerceiveResult();
            countResult.setNowRealNum(result1.getNowRealNum());
            countResult.setNowTestNum(result1.getNowTestNum());
            countResult.setTotalRealNum(result1.getTotalRealNum());
            countResult.setTotalTestNum(result1.getTotalTestNum());
            countResult.setTotalRate(result1.getTotalRate());
            return countResult;
        }


    }

    @Override
    public void deleteCache(String userId) {
        resultMap.remove(userId);
    }

    @Override
    public PutParam putParamer(String realCode, String testCode, Long beginTime, Long endTime) {

        PutParam param = new PutParam();
        param.setRealCode(realCode);
        param.setTestCode(testCode);
        param.setBeginTime(beginTime);
        param.setEndTime(endTime);
        return param;
    }


    private StatePerceiveResult statePerceiveCount(String userId,PutParam param,StatePerceiveResult result, Count countReal, Count countTest) {

        //找出真值系统和测试系统的创建时间
        long realCreateTime = countReal.getCreateTime();
        long testCreateTime = countTest.getCreateTime();
//        System.out.println(realCreateTime);
//        System.out.println(testCreateTime);
//        System.out.println(param.getBeginTime());
//        System.out.println(param.getEndTime());
        //如果两个时间都大于结束时间，说明仿真时间到，删除用户信息
        if (realCreateTime > param.getEndTime() && testCreateTime > param.getEndTime()){
            deleteCache(userId);
            return result;
        }



        // 如果真值系统系统当前帧且code与目标code相同有数据并且在仿真时间内
        if (countReal != null &&StringUtils.equals(countReal.getIotDeviceCode(), param.getRealCode()) &&realCreateTime >= param.getBeginTime() &&
                realCreateTime <= param.getEndTime()) {
            // 记录当前时间戳


            // 如果测试系统系统当前帧有数据且code与目标code相同有数据并且在仿真时间内
            if (countTest != null &&StringUtils.equals(countTest.getIotDeviceCode(), param.getTestCode())
            &&testCreateTime >= param.getBeginTime() && testCreateTime <= param.getEndTime()) {
                // 记录当前时间戳

                // 时间匹配上
                if (Math.abs(realCreateTime - testCreateTime) / 1000 < match_time) {
                    result = update(countReal, countTest, result);

                } else {
                    //时间没有匹配上，但是都有在要求时间范围内的数据，就把两个都加入缓存
                    result = AddCacheReal(result, testCreateTime, countReal, countTest);

                    result = AddCacheTest(result, realCreateTime, countReal, countTest);

                }


            } else {
                System.out.println("真值有数据，测试系统没有数据");
                // 如果被测系统没有数据
                result = AddCacheTest(result, realCreateTime, countReal, countTest);

            }


        } else {
            // 如果真值系统无数据
            if (countTest != null &&StringUtils.equals(countTest.getIotDeviceCode(), param.getTestCode())
                    &&testCreateTime >= param.getBeginTime() && testCreateTime <= param.getEndTime()) {
                System.out.println("真值无数据，测试有数据");
                // 测试系统有数据
                long test_createtime = countTest.getCreateTime();
                result = AddCacheReal(result, test_createtime, countReal, countTest);
            }
        }
        //删除已经匹配上的缓存
        result = deleteCache(result);
        result = changetTotalRate(result);

        return result;


    }

    /**
     * 从测试缓存中遍历找到是否有满足条件的数据，如果有满足条件的数据，则进行更新结果
     * @param result
     * @param real_createtime
     * @param countReal
     * @param countTest
     * @return
     */
    private StatePerceiveResult AddCacheTest(StatePerceiveResult result, long real_createtime, Count countReal, Count countTest) {
        Map<Long, Count> temp_real_dic = result.getTempRealDic();
        Map<Long, Count> temp_test_dic = result.getTempTestDic();
        List<Long> del_test_list = result.getDelTestList();
        if (!temp_test_dic.isEmpty()) {
            int min_time = match_time;
            Long min_test_key = 0L;
            for (Long test_time_key : temp_test_dic.keySet()) {
                float time_diff = Math.abs(test_time_key - real_createtime) / 1000;
                if (time_diff < min_time) {
                    min_time = (int) time_diff;
                    min_test_key = test_time_key;
                }
            }

            if (min_time < match_time) {
                del_test_list.add(min_test_key);
                countTest = temp_test_dic.get(min_test_key);
                result = update(countReal, countTest, result);
            } else {

                temp_real_dic.put(real_createtime, countReal);
            }
        } else {

            temp_real_dic.put(real_createtime, countReal);
        }

        result.setTempRealDic(temp_real_dic);
        result.setTempTestDic(temp_test_dic);
        result.setDelTestList(del_test_list);
        return result;
    }

    /**
     * 初始化数据All_real_num和All_test_num
     *
     * @param result
     * @return result
     */
    private StatePerceiveResult fillArray(StatePerceiveResult result) {
        for (int i = 0; i < 8; i++) {
            result.getAllRealNum().add(new ArrayList<>());
            result.getAllTestNum().add(new ArrayList<>());
        }
        return result;

    }

    /**
     * 更新正确率
     * @param result
     * @return
     */
    private StatePerceiveResult changetTotalRate(StatePerceiveResult result) {
        int[] totalRealNum = result.getTotalRealNum();
        int[] totalTestNum = result.getTotalTestNum();
        int[] totalRate = result.getTotalRate();
        int[] fenmuNum = result.getFenmuNum();
        int[] fenziNum = result.getFenziNum();
        for (int i = 0; i < 8; i++) {
            if (i < 4) {
                if (totalRealNum[i] > 0) {
                    totalRate[i] = changeSumData((double)totalTestNum[i] / (double)totalRealNum[i]);

                } else {
                    if (totalTestNum[i] == 0 && totalRealNum[i] == 0){
                        totalRate[i] = 100;
                    }

                }
            } else {
                if (fenmuNum[i] > 0) {
                    totalRate[i] = changeSumData(((double)fenziNum[i] / (double)fenmuNum[i]));

                } else {
                    if (fenziNum[i] == 0 && fenmuNum[i] == 0){
                        totalRate[i] = 100;
                    }

                }
            }
        }

        result.setTotalRate(totalRate);
        return result;


    }

    /**
     * 删除已经匹配的缓存
     *
     * @param
     * @param result
     */
    private StatePerceiveResult deleteCache(StatePerceiveResult result) {
        Map<Long, Count> temp_real_dic = result.getTempRealDic();
        Map<Long, Count> temp_test_dic = result.getTempTestDic();
        List<Long> del_real_list = result.getDelRealList();
        List<Long> del_test_list = result.getDelTestList();
        if (!del_real_list.isEmpty()) {
            for (Long dr : del_real_list) {
                temp_real_dic.remove(dr);
            }
        }
        if (!del_test_list.isEmpty()) {
            for (Long dr : del_test_list) {
                temp_test_dic.remove(dr);
            }
        }

        result.setTempRealDic(temp_real_dic);
        result.setTempTestDic(temp_test_dic);
        del_real_list.clear();
        del_test_list.clear();
        result.setDelRealList(del_real_list);
        result.setDelTestList(del_test_list);

        return result;
    }

    /**
     * 从真值缓存中遍历找到是否有满足条件的数据，如果有满足条件的数据，则进行更新结果
     * @param result
     * @param test_createtime
     * @param countReal
     * @param countTest
     * @return
     */
    private StatePerceiveResult AddCacheReal(StatePerceiveResult result, long test_createtime, Count countReal, Count countTest) {
        Map<Long, Count> temp_real_dic = result.getTempRealDic();
        Map<Long, Count> temp_test_dic = result.getTempTestDic();
        List<Long> del_real_list = result.getDelRealList();
        if (!temp_real_dic.isEmpty()) {
            int min_time = match_time;
            Long min_real_key = 0L;
            for (Long real_time_key : temp_real_dic.keySet()) {
                float time_diff = Math.abs(real_time_key - test_createtime) / 1000;
                if (time_diff < min_time) {
                    min_time = (int) time_diff;
                    min_real_key = real_time_key;
                }
            }
            if (min_time < match_time) {
                del_real_list.add(min_real_key);
                countReal = temp_real_dic.get(min_real_key);
                System.out.println("开始更新数据");
                result = update(countReal, countTest, result);
            } else {
                temp_test_dic.put(test_createtime, countTest);
            }
        } else {
            temp_test_dic.put(test_createtime, countTest);
        }
        result.setTempRealDic(temp_real_dic);
        result.setTempTestDic(temp_test_dic);
        result.setDelRealList(del_real_list);
        return result;

    }


    /**
     * 更新result里面的结果
     * @param countReal
     * @param countTest
     * @param result
     * @return
     */
    private StatePerceiveResult update(Count countReal, Count countTest, StatePerceiveResult result) {
        // 如果测试系统target_num小于真值系统的target_num，才计入统计信息
        // target_num 为目标车辆个数

        if (countTest.getTargetNum() <= countReal.getTargetNum()) {
            int targetNumReal = countReal.getTargetNum();
            int targetNumTest = countTest.getTargetNum();
            int[] nowRealNum = result.getNowRealNum();
            int[] nowTestNum = result.getNowTestNum();
            List<List<Integer>> allRealNum = result.getAllRealNum();
            List<List<Integer>> allTestNum = result.getAllTestNum();
            //更新当前数据的目标车辆数
            nowRealNum[target_num_index] = targetNumReal;
            nowTestNum[target_num_index] = targetNumTest;
            //将目标车辆数添加到存放全部数据的列表中
            allRealNum.get(target_num_index).add(targetNumReal);
            allTestNum.get(target_num_index).add(targetNumTest);

            result.setAllRealNum(allRealNum);
            result.setAllTestNum(allTestNum);
            result.setNowRealNum(nowRealNum);
            result.setNowTestNum(nowTestNum);


            // 满足设定的条件,真值系统的各种车型的数量均大于测试系统
            if (countReal.getSmallCarNum() >= countTest.getSmallCarNum() &&
                    countReal.getMidCarNum() >= countTest.getMidCarNum() &&
                    countReal.getBigCarNum() >= countTest.getBigCarNum()) {
                result = changeNum(countReal, countTest, result);
            }


        }
        return result;
    }

    private StatePerceiveResult changeNum(Count countReal, Count countTest, StatePerceiveResult result) {
        result = changNowNum(result, countReal, countTest);
        result = changeAllNum(result, countReal, countTest);
        result = AddFenmu(result);
        if ((Math.abs(countTest.getAvgSpeed() - countReal.getAvgSpeed()) <= avg_speed_thread)) {
            result = AddFenzi(result, avg_speed_index);
        }
        if ((Math.abs(countTest.getOccupancy() - countReal.getOccupancy()) <= occupancy_thread)) {
            result = AddFenzi(result, occupancy_index);
        }
        if ((Math.abs(countTest.getHeadway() - countReal.getHeadway()) <= headway_thread)) {
            result = AddFenzi(result, headway_index);
        }
        if ((Math.abs(countTest.getGap() - countReal.getGap()) <= gap_thread)) {
            result = AddFenzi(result, gap_index);
        }

        result = changetTotalNum(result);
        return result;


    }

    /**
     * 更新正确率的分子
     * @param result
     * @param index
     * @return
     */
    private StatePerceiveResult AddFenzi(StatePerceiveResult result, int index) {
        int[] fenzi_num = result.getFenziNum();
        fenzi_num[index] += 1;
        result.setFenziNum(fenzi_num);
        return result;
    }

    /**
     * 更新单位时间对比数据
     * @param result
     * @param countReal
     * @param countTest
     * @return
     */

    private StatePerceiveResult changNowNum(StatePerceiveResult result, Count countReal, Count countTest) {
        int[] now_real_num = result.getNowRealNum();
        int[] now_test_num = result.getNowTestNum();
        //更新当前数据的其他信息
        now_real_num[sum_smallcar_index] = countReal.getSmallCarNum();
        now_real_num[sum_midcar_index] = countReal.getMidCarNum();
        now_real_num[sum_bigcar_index] = countReal.getBigCarNum();
        now_real_num[avg_speed_index] =  (int)countReal.getAvgSpeed();
        now_real_num[occupancy_index] = (int) countReal.getOccupancy();
        now_real_num[headway_index] = (int) countReal.getHeadway();
        now_real_num[gap_index] = (int) countReal.getGap();
        now_test_num[sum_smallcar_index] = countTest.getSmallCarNum();
        now_test_num[sum_midcar_index] = countTest.getMidCarNum();
        now_test_num[sum_bigcar_index] = countTest.getBigCarNum();
        now_test_num[avg_speed_index] = (int) countTest.getAvgSpeed();
        now_test_num[occupancy_index] = (int) countTest.getOccupancy();
        now_test_num[headway_index] = (int) countTest.getHeadway();
        now_test_num[gap_index] = (int) countTest.getGap();


        result.setNowRealNum(now_real_num);
        result.setNowTestNum(now_test_num);
        return result;
    }

    /**
     * 更新累计数据结果
     * @param result
     * @return
     */
    private StatePerceiveResult changetTotalNum(StatePerceiveResult result) {
        List<List<Integer>> all_real_num = result.getAllRealNum();
        List<List<Integer>> all_test_num = result.getAllTestNum();
        int[] total_real_num = result.getTotalRealNum();
        int[] total_test_num = result.getTotalTestNum();
        int sum_real = 0;
        int sum_test = 0;
        for (int i = 0; i < total_real_num.length; i++) {
            List<Integer> longs_real = all_real_num.get(i);
            if (i < 4) {
                sum_real = longs_real.stream().reduce(Integer::sum).orElse(0);
                total_real_num[i] = changeSum(sum_real);
            } else {
                sum_real = longs_real.stream().reduce(Integer::sum).orElse(0);
                int result1 = sum_real / longs_real.size();
                total_real_num[i] = changeSum(result1);
            }

        }


        for (int i = 0; i < total_test_num.length; i++) {
            List<Integer> longs_test = all_test_num.get(i);
            if (i < 4) {
                sum_test = longs_test.stream().reduce(Integer::sum).orElse(0);
                total_test_num[i] = changeSum(sum_test);
            } else {
                sum_test = longs_test.stream().reduce(Integer::sum).orElse(0);
                int result2 = sum_test / longs_test.size();
                total_test_num[i] = changeSum(result2);
            }

        }
        result.setTotalRealNum(total_real_num);
        result.setTotalTestNum(total_test_num);
        return result;


    }

    /**
     * 保留两位小数
     * @param sum
     * @return
     */
    private int changeSumData(double sum) {
        String result = String.format("%.2f", sum);
        BigDecimal bdNum = new BigDecimal(result);
        return (int)Math.round(bdNum.doubleValue() * 100);
    }
    private int changeSum(int sum) {
        BigDecimal bg = new BigDecimal(sum);
        return (int)Math.round(bg.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue());
    }

    /**
     * 更新累计信息，全部信息list
     * @param result
     * @param countReal
     * @param countTest
     * @return
     */
    private StatePerceiveResult changeAllNum(StatePerceiveResult result, Count countReal, Count countTest) {

        List<List<Integer>> all_real_num = result.getAllRealNum();
        List<List<Integer>> all_test_num = result.getAllTestNum();
        all_real_num.get(sum_smallcar_index).add( countReal.getSmallCarNum());
        all_real_num.get(sum_midcar_index).add( countReal.getMidCarNum());
        all_real_num.get(sum_bigcar_index).add(countReal.getBigCarNum());
        all_real_num.get(avg_speed_index).add((int)countReal.getAvgSpeed());
        all_real_num.get(occupancy_index).add((int)countReal.getOccupancy());
        all_real_num.get(headway_index).add((int)countReal.getHeadway());
        all_real_num.get(gap_index).add((int)countReal.getGap());

        all_test_num.get(sum_smallcar_index).add( countTest.getSmallCarNum());
        all_test_num.get(sum_midcar_index).add( countTest.getMidCarNum());
        all_test_num.get(sum_bigcar_index).add( countTest.getBigCarNum());
        all_test_num.get(avg_speed_index).add((int)countTest.getAvgSpeed());
        all_test_num.get(occupancy_index).add((int)countTest.getOccupancy());
        all_test_num.get(headway_index).add((int)countTest.getHeadway());
        all_test_num.get(gap_index).add((int)countTest.getGap());

        result.setAllRealNum(all_real_num);
        result.setAllTestNum(all_test_num);
        return result;
    }

    /**
     * 增加正确率中的分母
     * @param result
     * @return
     */
    private StatePerceiveResult AddFenmu(StatePerceiveResult result) {
        int[] fenmu_num = result.getFenmuNum();
        for (int i = 1; i < 8; i++) {
            fenmu_num[i] += 1;
        }
        result.setFenmuNum(fenmu_num);
        return result;
    }

}
